#region Header
//=============================================================================
//                          GShield (Game Shield)
//=============================================================================
//
// Original Programmer: Shawn Jackson
// Company: WaveTech Digital Technologies (www.wtdt.com)
// Copyright: (c) 2006 WaveTech Digital Technologies, Inc. All Rights Reserved.
// Assembly: Engine
// Code File Name: ProcessHelper.cs
// Code File Date: 12/08/2006
//
// Code File Info: Windows Process Helper
//=============================================================================
/*
 * UPDATES
 * -------
 *    1.0.0.0 (ShawnJ) 4/18/2007: Added support for database based exeptions, ExceptionsDAO, instead of bumpers.
 *    0.9.0.x (ShawnJ) 5/5/2007: Refactoring for OSS.
 *    0.9.6.x (ShawnJ) 12/24/2007: Moved from EntLib to Linq
 */
#endregion Header

#region License

/*
  GShield - Game Shield
  Copyright (C) 2006-2007 WaveTech Digital Technologies, Inc.
                                http://www.wtdt.com

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#endregion License

#region Includes

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management;
using WaveTech.GShield.Data;
using WaveTech.GShield.Data.Collections;
using WaveTech.GShield.Model;

#endregion

namespace WaveTech.GShield.Engine
{
	public class ProcessHelper
	{
		#region Singleton

		private static readonly ProcessHelper instance = new ProcessHelper();

		#endregion Singleton

		#region Instance Property

		public static ProcessHelper Instance
		{
			get { return instance; }
		}

		#endregion Instance Property

		#region Constructor

		public ProcessHelper()
		{
			InitializeRequiredSystems();
		}

		#endregion Constructor

		#region Initialize Required Systems

		private void InitializeRequiredSystems()
		{
		}

		#endregion Initialize Required Systems

		#region Get Current Process Name

		public SortedList GetCurrentProcessesNames()
		{
			Process[] processes = Process.GetProcesses();
			SortedList names = new SortedList();

			foreach (Process p in processes)
			{
				names.Add(p.ProcessName, p.Id);
			}

			return names;
		}

		#endregion Get Current Process Name

		#region Does Process Exist

		/// <summary>
		/// Checkes the current system processes to determine if the
		/// supplied process exists.
		/// </summary>
		/// <param name="processName">Name of the process to check</param>
		/// <returns>True if the process can be found, else false.</returns>
		public bool DoesProcessExist(string processName)
		{
			bool doesExist = false;
			Process[] processes = Process.GetProcesses();

			foreach (Process p in processes)
			{
				if (p.ProcessName == processName)
					doesExist = true;
			}

			return doesExist;
		}

		#endregion Does Process Exist

		#region Get Current Processes Ids

		public ArrayList GetCurrentProcessesIds()
		{
			Process[] processes = Process.GetProcesses();
			ArrayList ids = new ArrayList();

			foreach (Process p in processes)
			{
				ids.Add(p.Id);
			}

			return ids;
		}

		#endregion Get Current Processes Ids

		#region Get Process By Id

		public GameProcess GetProcessById(int processId)
		{
			GameProcess o = new GameProcess();

			try
			{
				Process p = Process.GetProcessById(processId);

				o.Id = processId;
				o.Name = p.ProcessName;
				o.StartTime = p.StartTime;
				o.FullPath = p.MainModule.FileName;
				o.Company = p.MainModule.FileVersionInfo.CompanyName;
				o.InternalName = p.MainModule.FileVersionInfo.InternalName;
				o.ProductName = p.MainModule.FileVersionInfo.ProductName;

				o.Process = p;

				o.Modules = CreateGameModules(GetModulesForProcess(processId));
			}
			catch
			{
				return null;
			}

			return o;
		}

		#endregion Get Process By Id

		#region Create Game Modules

		private GameProcessModulesCollection CreateGameModules(ProcessModuleCollection modules)
		{
			GameProcessModulesCollection coll = new GameProcessModulesCollection();

			foreach (ProcessModule m in modules)
			{
				GameProcessModule gpm = new GameProcessModule();

				gpm.Name = m.ModuleName;
				gpm.FileName = m.FileName;

				coll.Add(gpm);
			}

			return coll;
		}

		#endregion Create Game Modules

		#region Get Modules For Process

		private ProcessModuleCollection GetModulesForProcess(int processId)
		{
			try
			{
				return Process.GetProcessById(processId).Modules;
			}
			catch
			{
				return null;
			}
		}

		#endregion Get Modules For Process

		#region Contains DirectX Module

		private bool ContainsDirectXModule(ProcessModuleCollection c)
		{
			bool usingDxInput = false;
			bool usingD3D = false;
			bool usingDxSound = false;

			if (c != null)
			{
				foreach (ProcessModule m in c)
				{
					if (m.ModuleName.ToLower().Contains("d3d"))
						usingD3D = true;
					else if (m.ModuleName.ToLower().Contains("dinput"))
						usingDxInput = true;
					else if (m.ModuleName.ToLower().Contains("dsound"))
						usingDxSound = true;
				}
			}

			if (usingD3D && usingDxSound)
				return true;
			else
				return false;
		}

		#endregion Contains DirectX Module

		#region Get DirectX Processes

		public GameProcessCollection GetDirectXProcesses()
		{
			GameProcessCollection games = new GameProcessCollection();

			GShieldDataContext db = new GShieldDataContext();
			List<string> exeptions = ExceptionsDAO.GetAllExceptionNames();

			ArrayList procsIds = GetCurrentProcessesIds();

			int i = 0;
			while (i < procsIds.Count)
			{
				GameProcess game;

				if (ContainsDirectXModule(GetModulesForProcess((int) procsIds[i])))
				{
					game = GetProcessById(int.Parse(procsIds[i].ToString()));

					bool okToAdd = false;

					foreach (object o in exeptions)
					{
						if (o != null && o.ToString().Length > 0)
						{
							if (game.Name.ToUpper() == o.ToString().ToUpper())
							{
								okToAdd = false;
								break;
							}
							else
								okToAdd = true;
						}
						else
						{
							okToAdd = true;
						}
					}

					if (okToAdd)
						games.Add(game);
				}
				i++;
			}

			if (games.Count <= 0)
				return null;
			else
				return games;
		}

		#endregion Get DirectX Processes

		#region Get Other Processes

		public GameProcessCollection GetOtherProcesses()
		{
			Setting s = SettingsDAO.Get();

			if (s.EnableOtherProcessWatcher.HasValue && s.EnableOtherProcessWatcher.Value)
			{
				GameProcessCollection games = new GameProcessCollection();
				ArrayList procsIds = GetCurrentProcessesIds();
				GameCollection sysgames = GamesDAO.GetAllGames();

				int i = 0;
				while (i < procsIds.Count)
				{
					GameProcess game = GetProcessById(int.Parse(procsIds[i].ToString()));

					bool okToAdd = false;

					if (game != null)
					{
						if (sysgames.IsProcessInList(game))
							okToAdd = true;

						if (okToAdd)
							games.Add(game);
					}

					i++;
				}

				if (games.Count <= 0)
					return null;
				else
					return games;
			}

			return null;
		}

		#endregion Get Other Processes

		#region Get OpenGL Processes

		public GameProcessCollection GetOpenGLProcesses()
		{
			GameProcessCollection games = new GameProcessCollection();
			List<string> exeptions = ExceptionsDAO.GetAllExceptionNames();

			ArrayList procsIds = GetCurrentProcessesIds();

			int i = 0;
			while (i < procsIds.Count)
			{
				GameProcess game;

				if (ContainsOpenGLModule(GetModulesForProcess((int) procsIds[i])))
				{
					game = GetProcessById(int.Parse(procsIds[i].ToString()));

					bool okToAdd = false;

					foreach (object o in exeptions)
					{
						if (o != null && o.ToString().Length > 0)
						{
							if (game.Name.ToUpper() == o.ToString().ToUpper())
							{
								okToAdd = false;
								break;
							}
							else
								okToAdd = true;
						}
						else
						{
							okToAdd = true;
						}
					}

					if (okToAdd)
						games.Add(game);
				}
				i++;
			}

			if (games.Count <= 0)
				return null;
			else
				return games;
		}

		#endregion Get OpenGL Processes

		#region Contains OpenGL Module

		private bool ContainsOpenGLModule(ProcessModuleCollection c)
		{
			bool usingOpenGL = false;

			if (c != null)
			{
				foreach (ProcessModule m in c)
				{
					// NVIDIA Compatible OpenGL ICD
					if (m.ModuleName.ToLower().Contains("nvoglnt"))
						usingOpenGL = true;
					else if (m.ModuleName.ToLower().Contains("nvoglv32"))
						usingOpenGL = true;
				}
			}

			if (usingOpenGL)
				return true;
			else
				return false;
		}

		#endregion Contains OpenGL Module

		#region Get Owner For Process

		public string GetOwnerForProcess(int? processId)
		{
			string User = String.Empty;
			string processname = String.Empty;

			try
			{
				ObjectQuery sq = new ObjectQuery("Select * from Win32_Process Where ProcessID = '" + processId + "'");
				ManagementObjectSearcher searcher = new ManagementObjectSearcher(sq);

				if (searcher.Get().Count == 0)
					return null;

				foreach (ManagementObject oReturn in searcher.Get())
				{
					string[] o = new String[2];

					//Invoke the method and populate the o var with the user name and domain
					oReturn.InvokeMethod("GetOwner", o);

					processname = (string) oReturn["Name"];
					User = o[0];
					if (User == null)
						User = String.Empty;

					return User;
				}
			}
			catch
			{
				return User;
			}
			return User;
		}

		#endregion Get Owner For Process

		#region Get All Game Processes

		/// <summary>
		/// Gets all the Game Processes (DirectX, OpenGL and Other) currently active
		/// </summary>
		/// <returns>Populated GameProcessCollection if games exist</returns>
		public GameProcessCollection GetAllGameProcesses()
		{
			GameProcessCollection games = new GameProcessCollection();

			GameProcessCollection directX = instance.GetDirectXProcesses();
			GameProcessCollection openGL = instance.GetOpenGLProcesses();
			GameProcessCollection other = instance.GetOtherProcesses();

			if (directX != null && directX.Count > 0)
				games.AddRange(directX);

			if (openGL != null && openGL.Count > 0)
				games.AddRange(openGL);

			if (other != null && other.Count > 0)
				games.AddRange(other);

			return games;
		}

		#endregion Get All Game Processes

		#region Kill Process

		public void KillProcess(int? processId)
		{
			Process p = Process.GetProcessById(processId.Value);
			p.Kill();
		}

		#endregion Kill Process
	}
}